
#pragma once

#include "Cond.hpp"
#include "Lock.hpp"
#include "Log.hpp"
#include "Thread.hpp"
#include "Task.hpp"

#include <iostream>
#include <pthread.h>
#include <vector>
#include <queue>
#include <memory>
#include <iterator>

using namespace LogMoudle;
using namespace ThreadMoudle;
using namespace LockModule;

// 在线程池中添加相应的单例模式

// 进一步更新加入单例模式

namespace ThreadPoolMoudle
{

    const static int DefaultNumber = 10;

    // T表示将要加入的任务
    template <typename T>

    class ThreadPool
    {
    private:
        int _thread_number;

        std::vector<Thread> _threads;
        std::queue<T> _taskqe;

        Cond _condlock;
        Mutex _mutex;

        int wait_number;
        bool isruning;

        static ThreadPool<T> *instance;
        static Mutex mutex; // 只用来保护单例

    private:
        void Hander_task(std::string name) // 对当前的任务进行处理
        {
            // 获取当前线程的名称
            //  std::string name= GetThreadNameFromNptl();
            LOG(Logevel::INFO) << name << "is runing....";

            while (true)
            {
                LockGuard lock(_mutex);

                while (_taskqe.empty() && isruning)
                {
                    wait_number++;
                    _condlock.Wait(_mutex);
                    wait_number--;
                }

                if (_taskqe.empty() && !isruning)
                {
                    break;
                }

                T t = _taskqe.front();
                _taskqe.pop();

                t();

                LOG(Logevel::INFO) << name << "get a task";
            }
        }
        ThreadPool(int thread_number = DefaultNumber) : _thread_number(thread_number),
                                                        wait_number(0), isruning(false)
        {

            LOG(Logevel::INFO) << "threadpool creat";
            
            for (int num = 0; num < _thread_number; num++)
            {
                _threads.emplace_back(std::bind(&ThreadPool::Hander_task, this, std::placeholders::_1));

                LOG(Logevel::INFO) << "init thread" << _threads.back().GetName();
            }
        }

    public:
        static ThreadPool<T> *GetInstance()
        {
            if (instance == nullptr)
            {
                LockModule::LockGuard lockguard(mutex);
                if (instance == nullptr)
                {
                    instance = new ThreadPool<T>();
                    instance->Start();
                    LOG(Logevel::INFO) << "创建单例线程池";
                    return instance;
                }
            }
            LOG(Logevel::INFO) << "获取线程池单例";
            return instance;
        }

        void Start()
        {
            isruning = true;
            for (auto &a : _threads)
            {
                a.Start();
                LOG(Logevel::INFO) << a.GetName() << " is start...";
            }
        }

        // 线程池退出
        void Stop()
        {
            if (isruning)
            {
                isruning = false;
                if (wait_number > 0)
                {
                    _condlock.NotifyAll();
                }
            }
        }

        // 线程退出
        void Wait()
        {
            for (auto &a : _threads)
            {
                a.Join();
                LOG(Logevel::INFO) << a.GetName() << " 退出....";
            }
        }

        bool Enqueue(const T &t)
        {
            bool ret = false;
            _mutex.Lock();
            if (isruning)
            {
                _taskqe.push(t);
                if (wait_number > 0)
                {
                    _condlock.Notify();
                }
                LOG(Logevel::INFO) << "任务加入队列";
                ret = true;
            }
            _mutex.UnLock();

            return ret;
        }
    };

    template <typename T>
    ThreadPool<T> *ThreadPool<T>::instance = NULL;

    template <typename T>
    LockModule::Mutex ThreadPool<T>::mutex; // 只用来保护单例

}